home *** CD-ROM | disk | FTP | other *** search
- /*
- * ThreadedSnakes.c
- *
- * Author: Brad Post
- * Creation Date: 12/16/92
- * Copyright © 1992, 1993 Apple Computer Inc.
- *
- * This file contains all the drawing routines for the snakes, as well as the initialization and
- * cleanup routines.
- * A special thanks goes out to David Anderson my Operating Systems Professor at Berkeley. His excellent
- * teachings helped me learn semaphores and light-weigth processes. I based this code on one of my programming
- * assignment in his class.
- */
-
- #include "ThreadedSnakes.h"
-
- /*
- * To choose which semaphore model to use, make any of the following equal to 1. To see some interesting side
- * effects, as described in drawSnake, make all of them 0.
- */
-
- #define SIMPLESNAKES 0
- #define LLSNAKES 1
- #define ARRAYSNAKES 0
-
- #define areaSize 25
-
- /* The snakes that we are going to run with. */
-
- SNAKE_ARGS snake1 = { {200, 50}, {2, 1}, 20, 350, kPreemptiveThread, { 0xDD6b, 0x8C2, 0x6a2 } };
- SNAKE_ARGS snake2 = { {10, 20}, {2, 1}, 20, 350, kPreemptiveThread, { 0, 0, 0xd400 } };
- SNAKE_ARGS snake3 = { {10, 100}, {2, 1}, 20, 350, kPreemptiveThread, { 0, 0, 0 } };
- SNAKE_ARGS snake4 = { {10, 260}, {2, 1}, 20, 350, kPreemptiveThread, { 0, 0x8000, 0x11b0 } };
- SNAKE_ARGS snake5 = { {260, 10}, {2, 1}, 20, 350, kPreemptiveThread, { 0x23c8, 0xfb1e, 0xffff } };
-
- /* Declare our semaphore as a global */
-
- #if LLSNAKES
- LinkedListSemaphorePtr theLLSemaphore;
- #elif SIMPLESNAKES
- SimpleSemaphorePtr theSimpleSemaphore;
- #elif ARRAYSNAKES
- ArraySemaphorePtr theArraySemaphore;
- #endif
-
- /*
- * cleanUpSnakes
- *
- * INPUT: void
- * RETURN: void
- *
- * This function is called when we quit, and all it does is dispose of the semaphore by
- * making the call to the proper function. The code is ugly, because I hack around my checks to
- * see if anyone is waiting on the semaphore. By making the waitingList = NULL in LinkedList
- * semaphores, we can then delete it. Also if you set the numberWaiting = 0 when using ArraySemaphores
- * you can delete them too.
- */
- void cleanUpSnakes()
- {
- ThreadBeginCritical();
- #if LLSNAKES
- if(DeleteLinkedListSemaphore( theLLSemaphore) != noErr)
- {
- theLLSemaphore->theHolder = kNoThreadID;
- theLLSemaphore->waitingList = NULL;
-
- if(DeleteLinkedListSemaphore( theLLSemaphore) != noErr)
- DebugStr("\pFailed to delete the LinkedList Semaphore");
- }
- #elif SIMPLESNAKES
- if(DeleteSimpleSemaphore( theSimpleSemaphore ) != noErr)
- DebugStr("\pFailed to delete the Simple Semaphore");
- #elif ARRAYSNAKES
- if( DeleteArraySemaphore( theArraySemaphore ) != noErr)
- {
- theArraySemaphore->numberWaiting = 0;
- if( DeleteArraySemaphore( theArraySemaphore ) != noErr)
- DebugStr("\pFailed to delete the Array Semaphore");
- }
- #endif
- ThreadEndCritical();
-
- ExitToShell();
- }
-
- /*
- * snakeMover
- *
- * INPUT: VEC, VEC
- * RETURN: void
- *
- * This function calculates the next position for the snake to move to. Depends on the velocity
- * of the snake.
- */
- snakeMover(VEC position, VEC velocity)
- {
- short i;
-
- for(i = 0; i < 2; i++)
- {
- position[i] += velocity[i];
- if((position[i] < 0) || ( (position[i] + 45) >= theBounds[i]))
- {
- velocity[i] = -velocity[i];
- position[i] += 2 * velocity[i];
- }
- }
- }
-
- /*
- * drawSnake
- *
- * INPUT: void *
- * RETURN: void
- *
- * This routing draws the snake. We either draw a RECTANGLE for COOPERATIVE threads, or an OVAL for
- * PREEMPTIVE threads. The color is determined by the snake characteristics. Now every thread calls this
- * routine, wether it's preemptive or not, and if you are running without semaphores, you see some ugly
- * side effects.
- * Now when you are running these with a semaphore model, you will see some of the snakes get drawn over.
- * This is because I didn't wish to make all the necessary calculations to see what type of snake, and
- * what color I am drawing over, and correctly draw the background color.
- *
- * NOTE: LOTS of ILLEGAL things are going on in this function during PREEMPTIVE THREAD execution.
- * DON'T TRY THIS AT HOME!!!! (Though I doubt you'll listen... :-)
- * SIDE EFFECTS: Since quickdraw is partially/kinda-sorta/re-entrant, we can, but don't quote me on this, call
- * this function during preemptive times. But we have some interesting side effects. To see them, make sure
- * you haven't selected any Semaphore model above, and you'll notice bars of colors starting to appear
- * on the screen as the snakes draw themselves. This is because the snakes are being interrupted and
- * Quickdraw is changing colors on the fly. You don't get this with the semaphore model, because every
- * snake needs to own the semaphore before it can draw, guarenteeing that it won't be interrupted and
- * Quickdraw won't change colors.
- * Also, if you are using the semaphore model, you might notice that the Preemptive threads appear to be
- * going slower. This is only because we are drawing an OVAL instead of a RECTANGLE.
- */
- pascal void *drawSnake(void *aSnake)
- {
- SNAKE_ARGS *theSnake = (SNAKE_ARGS *) aSnake; // the snake we are going to draw
- VEC elements[20] = { 0 }; // draw only 20 links of the snake then start erasing
- short index, // index into elements
- count; // count the number of moves we've made
- Rect rect; // rectangle to bounds either the OVAL or RECT we draw
- LinkedListElement iAmWaiting; // only used if using linkedlist semaphores
-
- for( ;; ) // loop forever
- {
- /*
- * Depending on the semaphore we are using, call the right function to get
- * the semaphore.
- */
- #if LLSNAKES
- GetLinkedListSemaphore(&iAmWaiting, theLLSemaphore);
- #elif SIMPLESNAKES
- GetSimpleSemaphore( theSimpleSemaphore );
- #elif ARRAYSNAKES
- GetArraySemaphore( theArraySemaphore );
- #endif
-
- // move the snakes for theSnake->numOfMoves until we release the semaphore
- for(count = 0; count < theSnake->numOfMoves; count++)
- {
- index = count % theSnake->length; // which segement are we on
-
- snakeMover(theSnake->pos, theSnake->vel); // where is the segment moving to?
-
- rect.left = elements[index][1]; // segements coordinates
- rect.top = elements[index][0];
- rect.bottom = rect.top + areaSize;
- rect.right = rect.left + areaSize;
-
- MoveTo(elements[index][1], elements[index][0]); // move to top, left corner of segement
-
- PenMode(patBic); // we are going to erase the segment
-
- RGBForeColor(&(theSnake->whatColor));
- if(theSnake->whatStyle == kCooperativeThread)
- PaintRect(&rect); // Draw a rectangle, symbolizing we are Cooperative
- else
- PaintOval(&rect); // Draw an oval, symbolizing we are Preemptive
-
- PenMode(patCopy); // going to draw the new segment
-
- elements[index][0] = theSnake->pos[0]; // set up for the new segment
- elements[index][1] = theSnake->pos[1];
-
- MoveTo(elements[index][1], elements[index][0]); // move to the top, left corner of segment
-
- rect.left = elements[index][1]; // set up the rect of the segment
- rect.top = elements[index][0];
- rect.bottom = rect.top + areaSize;
- rect.right = rect.left + areaSize;
-
- RGBForeColor(&(theSnake->whatColor));
- if(theSnake->whatStyle == kCooperativeThread)
- PaintRect(&rect); // Draw a rectangle, symbolizing we are Cooperative
- else
- PaintOval(&rect); // Draw an oval, symbolizing we are Preemptive
- }
-
- /*
- * Depending on the semaphore we are using, call the appropriate type
- * to release it.
- */
- #if LLSNAKES
- ReleaseLinkedListSemaphore(theLLSemaphore);
- #elif SIMPLESNAKES
- ReleaseSimpleSemaphore( theSimpleSemaphore );
- #elif ARRAYSNAKES
- ReleaseArraySemaphore( theArraySemaphore );
- #endif
- YieldToAnyThread();
- }
-
- }
-
- /*
- * initSnakes()
- *
- * INPUT: none
- * RETURN: void
- *
- * Creates a thread pool of 6 Cooperative and 6 Preemptive threads.
- * Aborts if failure.
- */
- void initSnakes()
- {
- OSErr theError;
- ThreadID the1ID, the2ID;
-
- /*
- * Start a critical section when creating threads, because if you don't, the minute you create
- * a preemptive thread, and it's in the ready state, it can preempt you. So either create
- * threads within a critical section, or create them all in the stopped state and wake them up
- * or .... be creative.....
- */
- ThreadBeginCritical();
-
- theError = CreateThreadPool(kCooperativeThread, 6, 0);
- if(theError != noErr)
- myError("\pCreating cooperative threads.");
-
-
- theError = CreateThreadPool(kPreemptiveThread, 6, 0);
- if(theError != noErr)
- myError("\pCreating preemptive threads.");
-
-
- theError = NewThread(snake1.whatStyle, drawSnake, (void *) &snake1, 0, kUsePremadeThread, NULL, &the1ID);
- if(theError != noErr)
- myError("\pCreating Snake1.");
-
-
- theError = NewThread(snake2.whatStyle, drawSnake, (void *) &snake2, 0, kUsePremadeThread, NULL, &the2ID);
- if(theError != noErr)
- myError("\pCreating Snake2.");
-
-
- theError = NewThread(snake3.whatStyle, drawSnake, (void *) &snake3, 0, kUsePremadeThread, NULL, &the2ID);
- if(theError != noErr)
- myError("\pCreating Snake3.");
-
-
- theError = NewThread(snake4.whatStyle, drawSnake, (void *) &snake4, 0, kUsePremadeThread, NULL, &the2ID);
- if(theError != noErr)
- myError("\pCreating Snake4.");
-
-
- theError = NewThread(snake5.whatStyle, drawSnake, (void *) &snake5, 0, kUsePremadeThread, NULL, &the2ID);
- if(theError != noErr)
- myError("\pCreating Snake5.");
-
-
- #if LLSNAKES
- if(CreateLinkedListSemaphore( &theLLSemaphore ) != noErr)
- DebugStr("\pFailed to create the LinkedList Semaphore");
- #elif SIMPLESNAKES
- if( CreateSimpleSemaphore( &theSimpleSemaphore ) != noErr)
- DebugStr("\pFailed to create the Simple Semaphore");
- #elif ARRAYSNAKES
- if( CreateArraySemaphore( 5, &theArraySemaphore) != noErr)
- DebugStr("\pFailed to create the Array Semaphore");
- #endif
-
- ThreadEndCritical();
-
- }
-
-
-